﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.WindowsAzure;
using Dokan;
using Microsoft.WindowsAzure.StorageClient;
using System.IO;

namespace AzureDriveCore
{
	public class AzureBlobController : AzureControllerBase
	{
		public AzureBlobController(CloudStorageAccount account)
			: base(account)
		{
			CloudBlobClient = account.CreateCloudBlobClient();
		}

		public CloudBlobClient CloudBlobClient;
		private BlobRequestOptions _metadataOptions = new BlobRequestOptions { BlobListingDetails = BlobListingDetails.Metadata, };

		private int _contextID = 0;
		public Dictionary<string, BlobRequestContext> RequestStore = new Dictionary<string, BlobRequestContext>();

		public override ControllerType Type
		{
			get { return ControllerType.Blob; }
		}

		public override RequestContextBase CreateDirectory(string filename)
		{
			var existingResult = GetFileOrDirectoryResult(filename);

			if (existingResult != null && existingResult.IsDirectory)
			{
				return existingResult.FileContext;
			}

			// Blob names must be lower cased.
			filename = filename.ToLower();

			// The directory doesn't already exist... so create it :)
			var containerReference = CloudBlobClient.GetContainerReference(filename);

			try
			{
				containerReference.CreateIfNotExist();

				var context = this.CreateRequest(filename);

				context.CreatedDate = DateTime.UtcNow;

				return context;
			}
			catch
			{
				return null;
			}
		}

		public override RequestContextBase CreateRequest(string path)
		{
			BlobRequestContext result;

			lock (RequestStore)
			{
				if (RequestStore.ContainsKey(path))
				{
					result = RequestStore[path];
				}
				else
				{
					result = new BlobRequestContext(this, path);

					result.ID = ++_contextID;

					RequestStore.Add(path, result);
				}

				result.IncrementLock();
			}

			return result;
		}

		public override FileOrDirectoryResult GetFileOrDirectoryResult(string path)
		{
			var context = this.CreateRequest(path);

			if (path == string.Empty)
			{
				return new FileOrDirectoryResult
				{
					// Need a context even if this is a directory.
					FileContext = context,
					IsDirectory = true,
				};
			}
			else
			{
				if (context.InitializeAsFile())
				{
					return new FileOrDirectoryResult
					{
						FileContext = context,
					};
				}
				else
				{
					if (CloudBlobClient.ContainerOrDirectoryExists(path))
					{
						return new FileOrDirectoryResult
						{
							// Need a context even if this is a directory.
							FileContext = context,
							IsDirectory = true,
						};
					}
					else
					{
						return null;
					}
				}
			}
		}

		public override List<FileInformation> FindFiles(string path)
		{
			var list = new List<FileInformation>();

			if (path == string.Empty)
			{
				try
				{
					foreach (var item in CloudBlobClient.ListContainers(null, ContainerListingDetails.Metadata))
					{
						list.Add(new FileInformation
						{
							Attributes = FileAttributes.Directory,
							CreationTime = item.Properties.LastModifiedUtc,
							FileName = item.Name,
							LastAccessTime = item.Properties.LastModifiedUtc,
							LastWriteTime = item.Properties.LastModifiedUtc,
						});
					}
				}
				catch { } // Exceptions == BlueScreen
			}
			else
			{
				try
				{
					foreach (var item in CloudBlobClient.GetBlobDirectoryReference(path).ListBlobs(_metadataOptions))
					{
						var itemDirectory = item as CloudBlobDirectory;
						var itemBlob = item as CloudBlob;

						if (itemDirectory != null)
						{
							var dateStamp = DateTime.UtcNow;
							var directoryName = itemDirectory.Uri.PathAndQuery.Substring(itemDirectory.Parent.Uri.PathAndQuery.Length);

							if (directoryName.EndsWith(@"/"))
							{
								directoryName = directoryName.Substring(0, directoryName.Length - 1);
							}

							list.Add(new FileInformation
							{
								Attributes = FileAttributes.Directory,
								CreationTime = dateStamp,
								FileName = directoryName,
								LastAccessTime = dateStamp,
								LastWriteTime = dateStamp,
							});
						}
						else if (itemBlob != null)
						{
							var fileName = Path.GetFileName(itemBlob.Name);

							list.Add(new FileInformation
							{
								Attributes = FileAttributes.Normal,
								CreationTime = itemBlob.Properties.LastModifiedUtc,
								FileName = fileName,
								Length = itemBlob.Properties.Length,
								LastAccessTime = itemBlob.Properties.LastModifiedUtc,
								LastWriteTime = itemBlob.Properties.LastModifiedUtc,
							});
						}
						else
						{
							Console.WriteLine("{0} :: {1}", item.Uri.PathAndQuery, item.GetType().Name);
						}
					}
				}
				catch { } // Exceptions == BlueScreen
			}

			return list;
		}
	}
}
